import {
  forwardRef,
  AfterContentInit,
  Component,
  ElementRef,
  HostBinding,
  Input,
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

export type ApesRadioGroupSizeType = 'large' | 'default' | 'small';
export type ApesRadioButtonStyle = 'outline' | 'solid';
import { isNotNil } from '../core/util/check';
import { toBoolean } from '../core/util/convert';

import { ApesRadioButtonComponent } from './apes-radio-button.component';
import { ApesRadioComponent } from './apes-radio.component';


@Component({
  selector: 'apes-radio-group',
  preserveWhitespaces: false,
  template: `
    <ng-content></ng-content>`,
  host: {
    '[class.apes-radio-group]': 'true',
  },
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => ApesRadioGroupComponent),
      multi: true,
    },
  ],
})
export class ApesRadioGroupComponent implements AfterContentInit, ControlValueAccessor {
  private _size: ApesRadioGroupSizeType = 'default';
  private _name: string;
  private _disabled: boolean;
  el: HTMLElement;
  value: string;

  // ngModel Access
  onChange: (_: string) => void = () => null;
  onTouched: () => void = () => null;

  radios: Array<ApesRadioComponent | ApesRadioButtonComponent> = [];

  @Input()
  set apesSize(value: ApesRadioGroupSizeType) {
    this._size = value;
  }

  get apesSize(): ApesRadioGroupSizeType {
    return this._size;
  }

  @Input()
  set apesDisabled(value: boolean) {
    this._disabled = toBoolean(value);
    this.updateDisabledState();
  }

  get apesDisabled(): boolean {
    return this._disabled;
  }

  @Input()
  set apesName(value: string) {
    this._name = value;
    this.updateChildrenName();
  }

  get apesName(): string {
    return this._name;
  }

  @Input() apesButtonStyle: ApesRadioButtonStyle = 'outline';

  updateDisabledState(): void {
    if (isNotNil(this.apesDisabled)) {
      this.radios.forEach((radio) => {
        radio.apesDisabled = this.apesDisabled;
      });
    }
  }

  updateChildrenName(): void {
    if (this.apesName) {
      this.radios.forEach((item) => {
        item.name = this.apesName;
      });
    }
  }

  syncCheckedValue(): void {
    this.radios.forEach((item) => {
      // @ts-ignore
      if (item.apesValue instanceof Object && this.value instanceof Object) {
        item.apesChecked = item.apesValue['id'] === this.value['id'];
      } else {
        item.apesChecked = item.apesValue === this.value;
      }
    });
  }

  @HostBinding('class.apes-radio-group-large')
  get isLarge(): boolean {
    return this.apesSize === 'large';
  }

  @HostBinding('class.apes-radio-group-small')
  get isSmall(): boolean {
    return this.apesSize === 'small';
  }

  @HostBinding('class.apes-radio-group-solid')
  get isSolid(): boolean {
    return this.apesButtonStyle === 'solid';
  }

  addRadio(radio: ApesRadioComponent | ApesRadioButtonComponent): void {
    this.radios.push(radio);
    radio.apesChecked = radio.apesValue === this.value;
  }

  selectRadio(radio: ApesRadioComponent | ApesRadioButtonComponent): void {
    this.updateValue(radio.apesValue, true);
  }

  updateValue(value: string, emit: boolean): void {
    this.value = value;
    this.syncCheckedValue();
    if (emit) {
      this.onChange(value);
    }
  }

  constructor(private elementRef: ElementRef) {
    this.el = this.elementRef.nativeElement;
  }

  ngAfterContentInit(): void {
    this.syncCheckedValue();
    this.updateChildrenName();
    Promise.resolve().then(() => {
      this.updateDisabledState();
    });
  }

  writeValue(value: string): void {
    this.updateValue(value, false);
  }

  registerOnChange(fn: (_: string) => void): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: () => void): void {
    this.onTouched = fn;
  }

  setDisabledState(isDisabled: boolean): void {
    this.apesDisabled = isDisabled;
  }

}
